为了在你的自定义 **CityPrimitive**
中添加重心坐标,你需要修改你的几何体数据,为每个顶点增加这些坐标。重心坐标是一个在三角形顶点上为 **[1, 0, 0]**
, **[0, 1, 0]**
, **[0, 0, 1]**
,并在内部插值的属性。这样,三角形的每个边上的坐标都会接近零,并且可以在片段着色器中用来判断一个片段是否接近边缘。
首先,你需要为你的几何体的每个三角形的顶点生成这些坐标。在 Cesium 中,可以在你创建顶点属性的时候添加这些坐标。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function generateBarycentricCoordinates (geometry ) { const numberOfVertices = Cesium .Geometry .computeNumberOfVertices (geometry); const barycentricCoordinates = new Float32Array (numberOfVertices * 3 ); for (let i = 0 , len = numberOfVertices / 3 ; i < len; ++i) { barycentricCoordinates[i * 9 + 0 ] = 1 ; barycentricCoordinates[i * 9 + 1 ] = 0 ; barycentricCoordinates[i * 9 + 2 ] = 0 ; barycentricCoordinates[i * 9 + 3 ] = 0 ; barycentricCoordinates[i * 9 + 4 ] = 1 ; barycentricCoordinates[i * 9 + 5 ] = 0 ; barycentricCoordinates[i * 9 + 6 ] = 0 ; barycentricCoordinates[i * 9 + 7 ] = 0 ; barycentricCoordinates[i * 9 + 8 ] = 1 ; } return new Cesium .GeometryAttribute ({ componentDatatype : Cesium .ComponentDatatype .FLOAT , componentsPerAttribute : 3 , values : barycentricCoordinates, }); } this .geometry .attributes .barycentric = generateBarycentricCoordinates (this .geometry );
接着,在你的 createCommand 函数中,你需要确保这个新属性被传递到着色器中,并且绑定到一个顶点着色器输入:
1 2 3 4 5 6 7 javascriptCopy code const attributeLocations = { position : 0 , normal : 1 , st : 2 , barycentric : 3 };
然后,在你的顶点着色器中,你需要接收并传递这个属性到片段着色器:
1 2 3 4 5 6 7 8 9 10 11 glslCopy code in vec3 barycentric; out vec3 v_barycentric;void main() { v_barycentric = barycentric; }
最后,在你的片段着色器中,你需要使用这个 v_barycentric 来确定是否绘制线框:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 glslCopy code in vec3 v_barycentric; void main() { float lineWidth = 0.01 ; if (min (min (v_barycentric.x, v_barycentric.y), v_barycentric.z) < lineWidth) { out_FragColor = vec4 (0.0 , 0.0 , 0.0 , 1.0 ); } else { discard ; } }
请记住,这些修改都需要适应你当前的代码和 Cesium 的使用方式。具体细节可能需要进一步调整以确保与你的应用程序兼容。
在 3D 图形学中, 重心坐标 (Barycentric coordinates)用于表示在三角形内部的点相对于三角形顶点的位置。一个点的重心坐标是三个数(通常记作 � , � , � u , v , w ),它们的和为 1,每个数对应于点在三角形一个顶点上的“权重”。在图形 API 中,重心坐标通常用于插值(如纹理坐标、颜色等)。
当给每个三角形的顶点赋予不同的重心坐标:
第一个顶点: ( 1 , 0 , 0 ) ( 1 , 0 , 0 )
第二个顶点: ( 0 , 1 , 0 ) ( 0 , 1 , 0 )
第三个顶点: ( 0 , 0 , 1 ) ( 0 , 0 , 1 )
在三角形的边上,至少有一个重心坐标将接近 0(因为边上的点只有两个顶点的“权重”)。在三角形内部,每个重心坐标都将大于 0。
所以,当你看到这样的代码:
1 2 3 4 glslCopy code if (min (min (v_barycentric.x, v_barycentric.y), v_barycentric.z) < lineWidth) { }
这段代码的意思是:如果在三个重心坐标中有任何一个接近 0(小于 lineWidth ),那么当前片段(Pixel)就处于三角形的边上或接近边缘。在这种情况下,如果你想渲染线框,你会在这些接近边缘的片段上应用一种颜色(如黑色),从而绘制出线框的效果。
而关于您的第一个问题,确实,这是一个顶点对应一个重心坐标,这三个顶点的重心坐标((1,0,0)(1,0,0), (0,1,0)(0,1,0), (0,0,1)(0,0,1))被分配给了三角形的三个顶点,这样可以在三角形内部以及边缘上插值这些坐标。当你在顶点着色器中将这些坐标传递到片段着色器,然后在片段着色器中使用这些坐标来检测边缘,你就能实现线框渲染的效果。